package com.zz.common;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import javax.xml.transform.Result;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLSyntaxErrorException;
import java.util.HashMap;
import java.util.Map;

/**
 * 全局异常处理
 * @author zhouzi
 */
@ControllerAdvice(annotations = {RestController.class,Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {

    private static int DUPLICATE_KEY_CODE = 1001;
    private static int PARAM_FAIL_CODE = 1002;
    private static int VALIDATION_CODE = 1003;

    //异常处理方法
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){
        log.error(ex.getMessage());

        //处理与数据库中重复的
        if(ex.getMessage().contains("Duplicate entry")){
            String[] split = ex.getMessage().split(" ");
            String msg = split[2]+"已存在";
            return R.error(msg);
        }

        return R.error("未知错误--->"+ex.getMessage());
    }

    //异常处理方法
    @ExceptionHandler(CustomException.class)
    public R<String> exceptionHandler(CustomException ex){
        log.error(ex.getMessage());

        return R.error(ex.getMessage());
    }

    /**
    *数据持久层异常处理
     */
    @ExceptionHandler(SQLException.class)
    public R<String> handlerSQLException(SQLException e){
        log.error("SQL语句异常=>>>{}", e.getMessage());
        return R.error("SQL语句异常--->"+e.getMessage());
    }

//    @ExceptionHandler(DataAccessException.class)
//    public R<String> handlerDataAccessException(DataAccessException e){
//        log.error("查询数据库失败=>>>{}",e.getMessage());
//        return R.error(e.getMessage());
//    }

    /**
    * 主键冲突
    * */
    @ExceptionHandler(DuplicateKeyException.class)
    public R<String> handlerDuplicateKeyException(DuplicateKeyException e){
        log.error(DUPLICATE_KEY_CODE+ "=>>>数据重复，请检查后提交");
        log.error("主键冲突，主键值已存在=>>>{}",e.getMessage());
        return R.error("主键冲突，主键值已存在--->"+e.getMessage());
    }

    /**
    * sql语法错误
    * */
    @ExceptionHandler(SQLSyntaxErrorException.class)
    public R<String> handlerSQLSyntaxErrorException(SQLSyntaxErrorException e){
        log.error("SQL语法错误=>>>{}",e.getMessage());
        return R.error("SQL语法错误--->"+e.getMessage());
    }


    /**
    * 空指针异常
    * */
    @ExceptionHandler(NullPointerException.class)
    public R<String> handlerNullPointerException(NullPointerException e){
        log.error("空指针异常=>>>{}", e.getMessage());
        return R.error("空指针异常--->"+e.getMessage());
    }


    //捕获无权限时候的异常
    @ExceptionHandler(value = AuthorizationException.class)
    @ResponseBody
    public Map<String, String> handleException(AuthorizationException e) {
        //e.printStackTrace();
        Map<String, String> result = new HashMap<String, String>();
        result.put("status", "400");
        //获取错误中中括号的内容
        String message = e.getMessage();
        String msg=message.substring(message.indexOf("[")+1,message.indexOf("]"));
        //判断是角色错误还是权限错误
        if (message.contains("role")) {
            result.put("msg", "对不起，您没有" + msg + "角色");
        } else if (message.contains("permission")) {
            result.put("msg", "对不起，您没有" + msg + "权限");
        } else {
            result.put("msg", "对不起，您的权限有误");
        }
        return result;
    }

    /**
     * 方法参数校验
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder stringBuilder = new StringBuilder("校验失败:");
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            stringBuilder.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(",");
        }

        String msg = stringBuilder.toString();

        log.error("参数校验失败"+e.getMessage());
        return R.error(msg+"参数校验失败--->"+e.getMessage());
    }

    /**
     * ValidationException
     */
    @ExceptionHandler(ValidationException.class)
    public R<String> handleValidationException(ValidationException e) {
        log.error(e.getMessage(), e);
        return R.error(VALIDATION_CODE+ "--->"+ e.getMessage());
    }

    /**
     * ConstraintViolationException
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public R<String> handleConstraintViolationException(ConstraintViolationException e) {
        log.error(e.getMessage(), e);
        return R.error(PARAM_FAIL_CODE+"--->"+ e.getMessage());
    }

    @ExceptionHandler(NoHandlerFoundException.class)
    public R<String> handlerNoFoundException(Exception e) {
        log.error(e.getMessage(), e);
        return R.error( "404--->路径不存在，请检查路径是否正确");
    }

    @ExceptionHandler(Exception.class)
    public R<String> handleException(Exception e) {
        log.error(e.getMessage(), e);
        return R.error( "500--->系统繁忙,请稍后再试,错误信息--->"+e.getMessage());
    }


}
